package com.pxst.tr.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.pxst.bank.entity.SysBankCardFlowEntity;
import com.pxst.bank.service.SysBankCardFlowEntityService;
import com.pxst.constants.TransactionConstant;
import com.pxst.exception.BusinessException;
import com.pxst.internalReports.entity.InternalTransferExcelEntity;
import com.pxst.internalReports.req.AddInternalTransferReq;
import com.pxst.internalReports.req.InternalTransferListReq;
import com.pxst.internalReports.resp.InternalTransferListResp;
import com.pxst.resp.ApiResp;
import com.pxst.resp.PageResp;
import com.pxst.tr.entity.SysIntroversionOrderEntity;
import com.pxst.tr.service.SysIntroversionOrderService;
import com.pxst.tr.mapper.SysIntroversionOrderMapper;
import com.pxst.utils.ExcelUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【sys_introversion_order(Transfer_内转订单(tr100))】的数据库操作Service实现
 * @createDate 2023-09-22 11:57:05
 */
@Service
public class SysIntroversionOrderServiceImpl extends ServiceImpl<SysIntroversionOrderMapper, SysIntroversionOrderEntity> implements SysIntroversionOrderService {

    @Resource
    private SysIntroversionOrderMapper sysIntroversionOrderMapper;

    @Autowired
    private SysBankCardFlowEntityService sysBankCardFlowEntityService;


    @Override
    public ApiResp<PageResp<InternalTransferListResp>> getInternalTransfer(InternalTransferListReq internalTransferListReq) {
        // 判断 getCompleted_start_time() 不为空，给status添加一个状态
        if (internalTransferListReq.getCompletedStartTime() != null) {
            internalTransferListReq.getStatus().add(TransactionConstant.STATUS_COMPLETED);
        }

        LambdaQueryWrapper<SysIntroversionOrderEntity> lam = new LambdaQueryWrapper<>();

        // 判断查询所需要的条件
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getCurrency())) {
            lam.eq(SysIntroversionOrderEntity::getCurrency, internalTransferListReq.getCurrency());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getAvailableBankId())) {
            lam.and(wrapper -> wrapper.exists("select * from `sys_bank_card` where `sys_introversion_order`.`from_bank_card_id` = `sys_bank_card`.`id` and\n" + "   exists ( select * from `sys_available_bank` where `sys_bank_card`.`bank_id` = `sys_available_bank`.`bank_id` and `bank_id` = 3 )").or().exists("select * from `sys_bank_card` where `sys_introversion_order`.`to_bank_card_id` = `sys_bank_card`.`id` and\n" + "   exists ( select * from `sys_available_bank` where `sys_bank_card`.`bank_id` = `sys_available_bank`.`bank_id` and `bank_id` = 3 )"));
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getFrom())) {
            lam.exists(MessageFormat.format("select * from `sys_bank_card` where `sys_introversion_order`.`from_bank_card_id` = `sys_bank_card`.`id`" + "and `account_code` like %{0}%", internalTransferListReq.getFrom()));
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getTo())) {
            lam.exists(MessageFormat.format("select * from `sys_bank_card` where `sys_introversion_order`.`to_bank_card_id` = `sys_bank_card`.`id`" + "and `account_code` like %{0}%", internalTransferListReq.getTo()));
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getBankCardGroupId())) {
            lam.ge(SysIntroversionOrderEntity::getUpdatedAt, internalTransferListReq.getUpdatedStartDate());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getUpdatedEndDate())) {
            lam.le(SysIntroversionOrderEntity::getUpdatedAt, internalTransferListReq.getUpdatedEndDate());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getCompletedStartTime())) {
            lam.ge(SysIntroversionOrderEntity::getCompletedAt, internalTransferListReq.getCompletedStartTime());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getCompletedEndTime())) {
            lam.le(SysIntroversionOrderEntity::getCompletedAt, internalTransferListReq.getCompletedEndTime());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getVndOtp())) {
            lam.in(SysIntroversionOrderEntity::getVndOtp, internalTransferListReq.getVndOtp());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getVndPaymentMethod())) {
            lam.in(SysIntroversionOrderEntity::getVndPaymentMethod, internalTransferListReq.getVndPaymentMethod());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getPostscript())) {
            lam.like(SysIntroversionOrderEntity::getPostscript, internalTransferListReq.getPostscript());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getAltId())) {
            List<String> split = StrUtil.split(internalTransferListReq.getAltId(), "|");
            lam.in(SysIntroversionOrderEntity::getId, split);
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getTrAuto())) {
            lam.eq(SysIntroversionOrderEntity::getTrAuto, 1);
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getFrom())) {
            if (internalTransferListReq.getVbsTag() == 1) {
                lam.isNotNull(SysIntroversionOrderEntity::getFromVsId).isNotNull(SysIntroversionOrderEntity::getToVsId);
            } else if (internalTransferListReq.getVbsTag() == 2) {
                lam.isNull(SysIntroversionOrderEntity::getFromVsId).or().isNull(SysIntroversionOrderEntity::getToVsId);
            }
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getStatus())) {
            lam.in(SysIntroversionOrderEntity::getStatus, internalTransferListReq.getStatus());
        }
        if (ObjectUtils.isNotEmpty(internalTransferListReq.getType())) {
            lam.in(SysIntroversionOrderEntity::getType, internalTransferListReq.getType());
        }

        // 查询分页数据
        PageHelper.startPage(internalTransferListReq.getPage(), internalTransferListReq.getRp());
        Page<SysIntroversionOrderEntity> sysIntroversionOrderEntities = (Page<SysIntroversionOrderEntity>) sysIntroversionOrderMapper.selectList(lam);

        // 创建一个集合，用于将查询到的数据转换为需要的数据
        List<InternalTransferListResp> internalTransferListResps = new ArrayList<>();

        // 判断查询到的数据是否为空，不为空，则将查询到的数据转换为需要的数据
        if (ObjectUtils.isNotEmpty(sysIntroversionOrderEntities.getResult())) {
            internalTransferListResps = sysIntroversionOrderEntities.getResult().stream().map(iter -> {
                InternalTransferListResp internalTransferListResp = new InternalTransferListResp();
                BeanUtils.copyProperties(iter, internalTransferListResp);
                internalTransferListResp.setTrId(iter.getId());//字段的名称不一致无法复制导入
                return internalTransferListResp;
            }).collect(Collectors.toList());
        }
        return ApiResp.page(sysIntroversionOrderEntities.getPageNum(), sysIntroversionOrderEntities.getPageSize(), (int) sysIntroversionOrderEntities.getTotal(), internalTransferListResps);
    }

    /**
     * @param internalTransferListReq
     * @param response
     * @author Chrissy
     */
    @Override
    public void downloadInternalTransfer(InternalTransferListReq internalTransferListReq, HttpServletResponse response) {
        // 判断 getCompleted_start_time() 不为空，给status添加一个状态
        if (internalTransferListReq.getCompletedStartTime() != null) {
            internalTransferListReq.getStatus().add(TransactionConstant.STATUS_COMPLETED);
        }

        LambdaQueryWrapper<SysIntroversionOrderEntity> lam = new LambdaQueryWrapper<>();

        // 判断查询所需要的条件
        lam.eq(ObjectUtils.isNotEmpty(internalTransferListReq.getCurrency()), SysIntroversionOrderEntity::getCurrency, internalTransferListReq.getCurrency());
        lam.and(ObjectUtils.isNotEmpty(internalTransferListReq.getAvailableBankId()), wrapper -> wrapper.exists("select * from `sys_bank_card` where `sys_introversion_order`.`from_bank_card_id` = `sys_bank_card`.`id` and\n" + "   exists ( select * from `sys_available_bank` where `sys_bank_card`.`bank_id` = `sys_available_bank`.`bank_id` and `bank_id` = 3 )").or().exists("select * from `sys_bank_card` where `sys_introversion_order`.`to_bank_card_id` = `sys_bank_card`.`id` and\n" + "   exists ( select * from `sys_available_bank` where `sys_bank_card`.`bank_id` = `sys_available_bank`.`bank_id` and `bank_id` = 3 )"));
        lam.exists(ObjectUtils.isNotEmpty(internalTransferListReq.getFrom()), MessageFormat.format("select * from `sys_bank_card` where `sys_introversion_order`.`from_bank_card_id` = `sys_bank_card`.`id`" + "and `account_code` like %{0}%", internalTransferListReq.getFrom()));
        lam.exists(ObjectUtils.isNotEmpty(internalTransferListReq.getTo()), MessageFormat.format("select * from `sys_bank_card` where `sys_introversion_order`.`to_bank_card_id` = `sys_bank_card`.`id`" + "and `account_code` like %{0}%", internalTransferListReq.getTo()));
        lam.ge(ObjectUtils.isNotEmpty(internalTransferListReq.getBankCardGroupId()), SysIntroversionOrderEntity::getUpdatedAt, internalTransferListReq.getUpdatedStartDate());
        lam.le(ObjectUtils.isNotEmpty(internalTransferListReq.getUpdatedEndDate()), SysIntroversionOrderEntity::getUpdatedAt, internalTransferListReq.getUpdatedEndDate());
        lam.ge(ObjectUtils.isNotEmpty(internalTransferListReq.getCompletedStartTime()), SysIntroversionOrderEntity::getCompletedAt, internalTransferListReq.getCompletedStartTime());
        lam.le(ObjectUtils.isNotEmpty(internalTransferListReq.getCompletedEndTime()), SysIntroversionOrderEntity::getCompletedAt, internalTransferListReq.getCompletedEndTime());
        lam.in(ObjectUtils.isNotEmpty(internalTransferListReq.getVndOtp()), SysIntroversionOrderEntity::getVndOtp, internalTransferListReq.getVndOtp());
        lam.in(ObjectUtils.isNotEmpty(internalTransferListReq.getVndPaymentMethod()), SysIntroversionOrderEntity::getVndPaymentMethod, internalTransferListReq.getVndPaymentMethod());
        lam.like(ObjectUtils.isNotEmpty(internalTransferListReq.getPostscript()), SysIntroversionOrderEntity::getPostscript, internalTransferListReq.getPostscript());
        lam.eq(ObjectUtils.isNotEmpty(internalTransferListReq.getTrAuto()), SysIntroversionOrderEntity::getTrAuto, 1);
        lam.in(ObjectUtils.isNotEmpty(internalTransferListReq.getStatus()), SysIntroversionOrderEntity::getStatus, internalTransferListReq.getStatus());
        lam.in(ObjectUtils.isNotEmpty(internalTransferListReq.getType()), SysIntroversionOrderEntity::getType, internalTransferListReq.getType());
        //这里对altId进行拆分
        List<String> split = StrUtil.split(internalTransferListReq.getAltId(), "|");
        lam.in(ObjectUtils.isNotEmpty(internalTransferListReq.getAltId()), SysIntroversionOrderEntity::getId, split);

        if (ObjectUtils.isNotEmpty(internalTransferListReq.getFrom())) {
            if (internalTransferListReq.getVbsTag() == 1) {
                lam.isNotNull(SysIntroversionOrderEntity::getFromVsId).isNotNull(SysIntroversionOrderEntity::getToVsId);
            } else if (internalTransferListReq.getVbsTag() == 2) {
                lam.isNull(SysIntroversionOrderEntity::getFromVsId).or().isNull(SysIntroversionOrderEntity::getToVsId);
            }
        }

        // 查询指定条件的全部数据
        List<SysIntroversionOrderEntity> result = sysIntroversionOrderMapper.selectList(lam);

        // 创建一个集合，用于将查询到的数据转换为需要的数据
        List<InternalTransferListResp> internalTransferListResps = new ArrayList<>();

        //创建一个Excel模版集合
        List<InternalTransferExcelEntity> internalTransferExcelEntities = new ArrayList<>();

        // 判断查询到的数据是否为空，不为空，则将查询到的数据转换为需要的数据
        if (ObjectUtils.isNotEmpty(result)) {
            //把内转订单里面的数据拿出来进行处理
            internalTransferListResps = result.stream().map(iter -> {
                InternalTransferListResp internalTransferListResp = new InternalTransferListResp();
                BeanUtils.copyProperties(iter, internalTransferListResp);//用于对internalTransferListResp对象进行属性赋值
                internalTransferListResp.setTrId(iter.getId());
                return internalTransferListResp;
            }).collect(Collectors.toList());

            //获取处理好的Excel模型对象的列表数据
            internalTransferExcelEntities = internalTransferListResps.stream().map(iter -> {
                InternalTransferExcelEntity internalTransferExcelEntity = new InternalTransferExcelEntity();
                BeanUtils.copyProperties(iter, internalTransferExcelEntity);//复制属性数据（能复制的）
                internalTransferExcelEntity.setId(iter.getTrId()).setInfo(iter.getNote() + "\n" + iter.getPostscript());//info字段需要整合多个字段的数据
                return internalTransferExcelEntity;
            }).collect(Collectors.toList());
        }

        //创建汇出表的文件名
        String fileName = "TR-";

        try {
            //尝试导出表
            ExcelUtils.exportExcel(internalTransferExcelEntities, null, "Worksheet", InternalTransferExcelEntity.class, fileName, response);
        } catch (IOException e) {
            e.printStackTrace();
            log.error(fileName + ".xlsx 表导出失败");
        }
    }


    /**
     * 新增操作开启事务回滚支持
     *
     * @param addInternalTransferReq
     * @return
     * @author Chrissy
     */
    @Transactional(rollbackOn = {Exception.class})
    @Override
    public synchronized ApiResp addInternalTransferList(AddInternalTransferReq addInternalTransferReq) {
        /**
         * 总体业务逻辑:先校验后转账
         */

        /**
         * 检验逻辑
         */
        //1.检查发起者和接收者的Id是否相同
        if (addInternalTransferReq.getFromBankCardId() == addInternalTransferReq.getToBankCardId()) {
            throw new BusinessException("转入用户与转出用户不可相同！");
        }

        /**
         * 这里复用了预检的逻辑
         */
        //检查发起者的日转金额
        //检查发起者的日转次数
        //检查接受者的日收金额
        //检查接受者的日收次数
        //检查发起者的余额
        //检查接受者接收余额后是否达到上限
        //检查发起的金额是否在发起者银行支持范围内
        //检查接受的金额是否在接受者银行支持范围内
        sysBankCardFlowEntityService.checkLimit(addInternalTransferReq.getFromBankCardId(), addInternalTransferReq.getToBankCardId(), addInternalTransferReq.getRequestAmount());

        /**
         * 转账逻辑
         */
        /**
         * 查询出发起者的流水信息
         */
        SysBankCardFlowEntity fromFlow = sysBankCardFlowEntityService.getById(addInternalTransferReq.getFromBankCardId());


        /**
         * 查询出接收者的流水信息
         */
        SysBankCardFlowEntity toFlow = sysBankCardFlowEntityService.getById(addInternalTransferReq.getToBankCardId());

        /**
         * 新建内转订单记录
         */
        //1.创建新订单对象
        SysIntroversionOrderEntity sysIntroversionOrderEntity = new SysIntroversionOrderEntity();
        //2.设置交易前信息
        //from交易前余额
        sysIntroversionOrderEntity.setPreBalanceFrom(fromFlow.getBalance());
        //from交易前讯银余额
        sysIntroversionOrderEntity.setBalanceFromXy(fromFlow.getXyBalance());
        //to交易前余额
        sysIntroversionOrderEntity.setPreBalanceTo(toFlow.getBalance());
        //to交易前讯银余额
        sysIntroversionOrderEntity.setPreBalanceToXy(toFlow.getXyBalance());


        //1.发起转账者的日流水修改
        fromFlow.setDayFlowOut(fromFlow.getDayFlowOut().add(addInternalTransferReq.getRequestAmount()));
        //2.发起转折者的月流水修改
        fromFlow.setMonthFlowOut(fromFlow.getMonthFlowOut().add(addInternalTransferReq.getRequestAmount()));
        //3.发起转账者的日成功次数修改
        fromFlow.setDaySuccessOutCount(fromFlow.getDaySuccessOutCount() + 1);
        //4.发起转账者的月成功次数修改
        fromFlow.setMonthSuccessOutCount(fromFlow.getMonthSuccessOutCount() + 1);
        //5.发起转账者的今日支付金额修改
        fromFlow.setTotalDayDebit(fromFlow.getTotalDayDebit().add(addInternalTransferReq.getRequestAmount()));
        //6.发起转账者账户余额修改
        fromFlow.setBalance(fromFlow.getBalance().subtract(addInternalTransferReq.getRequestAmount()));

        //7.发起转账者更新者以及更新时间的修改
        fromFlow.setUpdater(addInternalTransferReq.getOperator());
        fromFlow.setUpdatedAt(new Date());


        //8.接收转账者的日流水修改
        toFlow.setDayFlowIn(toFlow.getDayFlowIn().add(addInternalTransferReq.getRequestAmount()));

        //9.接收转账者的月流水修改
        toFlow.setMonthFlowIn(toFlow.getMonthFlowIn().add(addInternalTransferReq.getRequestAmount()));

        //10.接收转账者的日成功次数修改
        toFlow.setDaySuccessInCount(toFlow.getDaySuccessInCount() + 1);

        //11.接受转账者的月成功次数修改
        toFlow.setMonthSuccessInCount(toFlow.getMonthSuccessInCount() + 1);

        //12.接受转账者的今日收款金额修改
        toFlow.setTotalDayCredit(toFlow.getTotalDayCredit().add(addInternalTransferReq.getRequestAmount()));

        //13.接受转账者的账户余额修改
        toFlow.setBalance(toFlow.getBalance().subtract(addInternalTransferReq.getRequestAmount()));

        //14.接收转账者的更新时间的修改
        toFlow.setUpdatedAt(new Date());

        //15.接收转账者的更新操作者的修改
        toFlow.setUpdater(addInternalTransferReq.getOperator());

        /**
         * 继续添加内转订单信息
         */
        // 1.交易后from余额
        sysIntroversionOrderEntity.setBalanceFrom(fromFlow.getBalance());

        // 2.交易后to余额
        sysIntroversionOrderEntity.setBalanceTo(toFlow.getBalance());

        // 3.设置用户发起金额
        sysIntroversionOrderEntity.setRequestAmount(addInternalTransferReq.getRequestAmount());

        // 4.设置实际作用金额（暂时统一为用户发起金额）
        sysIntroversionOrderEntity.setPaidAmount(addInternalTransferReq.getRequestAmount());

        // 5.手续费不知道就没写
        sysIntroversionOrderEntity.setRate(BigDecimal.valueOf(0));
        sysIntroversionOrderEntity.setBankFee(BigDecimal.valueOf(0));

        // 6.设置交易完成时间
        sysIntroversionOrderEntity.setCompletedAt(new Date());

        // 7.设置币别
        sysIntroversionOrderEntity.setCurrency(addInternalTransferReq.getCurrency());

        // 8.设置手动状态
        sysIntroversionOrderEntity.setAction(addInternalTransferReq.getCreateMode());

        // 9.设置备注
        sysIntroversionOrderEntity.setNote(addInternalTransferReq.getNote());

        // 10.设置创建人员和更新人员（因为新创建所以统一为一个人）
        sysIntroversionOrderEntity.setCreator(addInternalTransferReq.getOperator());
        sysIntroversionOrderEntity.setUpdater(addInternalTransferReq.getOperator());

        // 11.设置创建时间和更新时间
        sysIntroversionOrderEntity.setCreatedAt(new Date());
        sysIntroversionOrderEntity.setUpdatedAt(new Date());

        // 12.本地当前时间暂不设置，后面看根据什么条件来设置（Tips：我感觉是根据币别然后手动定时差）
        sysIntroversionOrderEntity.setLocalCreatedAt(null);
        sysIntroversionOrderEntity.setLocalUpdatedAt(null);

        // 13.设置执行次数
        sysIntroversionOrderEntity.setRetryTimes(1);

        int insert = sysIntroversionOrderMapper.insert(sysIntroversionOrderEntity);

        if (insert == 1) {
            return ApiResp.sucess();
        } else {
            throw new BusinessException("新增异常，请检查信息！");
        }
    }
}




